//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.tuiofx.internal.gesture;

import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.animation.Animation.Status;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.MapChangeListener;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.event.EventTarget;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseDragEvent;
import javafx.scene.input.MouseEvent;
import javafx.util.Duration;
import org.tuiofx.Configuration;
import org.tuiofx.internal.util.LogUtils;
import org.tuiofx.internal.util.Util;

public class MouseEventRecognizer extends GestureRecognizer {
    private final LongPressDetector longPressDetector;
    private Map<EventTarget, ClickCounter> counters = new HashMap<>();
    private boolean mouseExited = false;
    private TuioTouchPoint mouseDraggedTouchPoint;
    private volatile DragDetectedState dragDetected;
    private double originNextMouseDraggedSceneX;
    private double originNextMouseDraggedSceneY;
    private double originNextMouseDraggedScreenX;
    private double originNextMouseDraggedScreenY;
    private final Queue<CacheEventData> stoppingTouchPoints;
    private TuioTouchPoint firstTouchPoint;
    private boolean fullPDREntered;
    private EventTarget fullPDRCurrentTarget;
    private EventTarget fullPDRSource;
    private final List<EventTarget> fullPDRNewEventTargets;
    private final List<EventTarget> fullPDRCurrentEventTargets;

    public MouseEventRecognizer(final Node targetNode, Configuration config) {
        super(targetNode, config);
        this.dragDetected = MouseEventRecognizer.DragDetectedState.NOT_YET;
        this.stoppingTouchPoints = new LinkedList<>();
        this.fullPDREntered = false;
        this.fullPDRCurrentTarget = null;
        this.fullPDRNewEventTargets = new ArrayList<>();
        this.fullPDRCurrentEventTargets = new ArrayList<>();
        this.requiredNumberOfTouches = 1;
        this.longPressDetector = new LongPressDetector(config.getLongPressDuration());
        this.longPressDetector.getTimeline().statusProperty().addListener(new ChangeListener<Animation.Status>() {
            public void changed(ObservableValue<? extends Animation.Status> observable, Animation.Status oldValue, Animation.Status newValue) {
                if (newValue.equals(Status.STOPPED)) {
                    TuioTouchPoint tPoint = MouseEventRecognizer.this.longPressDetector.getLongPressTouchPoint();
                    MouseEventRecognizer.this._touchesBegan(tPoint);
                }

            }
        });
        targetNode.getProperties().addListener(new MapChangeListener<Object, Object>() {
            public void onChanged(MapChangeListener.Change<? extends Object, ? extends Object> change) {
                if (change.getKey().equals("startFullDrag") && change.getValueAdded().toString().equals("true")) {
                    MouseEventRecognizer.this.startFullDrag(targetNode);
                }

            }
        });
    }

    private void fillHierarchy(List<EventTarget> list, Node node) {
        list.clear();

        Parent p;
        for (Node n = node; n != null; n = p) {
            list.add(n);
            p = ((Node) n).getParent();
        }

        if (this.scene != null) {
            list.add(this.scene);
        }

    }

    public void touchesBegan(TuioTouchPoint touchPoint) {
        if (this.touchPointsCount == 1) {
            this.firstTouchPoint = touchPoint;
            MouseButton button = MouseButton.NONE;
            this.fireMouseEvent(touchPoint, MouseEvent.MOUSE_ENTERED_TARGET, false, false, false, 0, button);
            ClickCounter counter = this.createClickCounter((Node) touchPoint.getTargetNode());
            counter.start(touchPoint.getSceneX(), touchPoint.getSceneY());
        }

        this.longPressDetector.touchesBegan(touchPoint);
        if (!this.longPressDetector.isRunning()) {
            if (this.touchPointsCount > this.requiredNumberOfTouches) {
            }

        }
    }

    private void _touchesBegan(TuioTouchPoint touchPoint) {
        boolean longpressDetected = this.longPressDetector.getLongpressDetected().getValue();
        if (this.touchPointsCount == this.requiredNumberOfTouches || !longpressDetected && this.touchPointsCount == 0) {
            ClickCounter counter = this.counters.get(touchPoint.getTargetNode());
            if (counter == null) {
                LogUtils.error("Counter should not be null >> _touchesBegan");
                return;
            }

            int clickCount = counter.getClickCount();
            boolean stillSincePress = counter.isStill();
            MouseButton button = !longpressDetected ? MouseButton.PRIMARY : MouseButton.SECONDARY;
            this.fireMouseEvent(touchPoint, MouseEvent.MOUSE_PRESSED, !longpressDetected, longpressDetected, stillSincePress, clickCount, button);
            if (longpressDetected) {
                this.fireContextEventMenu(touchPoint);
            }
        }

    }

    private ClickCounter createClickCounter(Node targetNode) {
        ClickCounter counter = this.counters.get(targetNode);
        if (counter == null) {
            counter = new ClickCounter();
            this.counters.put(targetNode, counter);
        }

        return counter;
    }

    public void touchesMove(TuioTouchPoint touchPoint) {
        this.longPressDetector.touchesMove(touchPoint);
        if (!this.longPressDetector.isRunning() && this.stoppingTouchPoints.isEmpty()) {
            this.mouseDragged(touchPoint);
        }

        ClickCounter counter = this.counters.get(touchPoint.getTargetNode());
        if (counter == null) {
            LogUtils.error("Counter should not be null >> touchesMove");
        } else {
            counter.moved(touchPoint.getSceneX(), touchPoint.getSceneY());
            EventTarget currentTargetNode = touchPoint.getCurrentTargetNode();
            if (currentTargetNode != null) {
                if (!this.getTargetNode().equals(currentTargetNode) && !this.mouseExited) {
                    this.fireMouseEvent(touchPoint, MouseEvent.MOUSE_EXITED, true, false, false, 0, MouseButton.PRIMARY);
                    this.mouseExited = true;
                }

            }
        }
    }

    public void touchesEnd(TuioTouchPoint touchPoint) {
        this.longPressDetector.touchesEnd(touchPoint);
        if (this.touchPointsCount > 0) {
            this.originNextMouseDraggedSceneX = ((TuioTouchPoint) this.touchPointsList.get(0)).getSceneX();
            this.originNextMouseDraggedSceneY = ((TuioTouchPoint) this.touchPointsList.get(0)).getSceneY();
            this.originNextMouseDraggedScreenX = ((TuioTouchPoint) this.touchPointsList.get(0)).getScreenX();
            this.originNextMouseDraggedScreenY = ((TuioTouchPoint) this.touchPointsList.get(0)).getScreenY();
        } else if (this.touchPointsCount == 0) {
            this.mouseDraggedTouchPoint = null;
        }

        if (this.touchPointsCount == 0 && this.firstTouchPoint.equals(touchPoint)) {
            ClickCounter counter = this.counters.get(touchPoint.getTargetNode());
            if (counter == null) {
                LogUtils.error("++++ Counter for target " + touchPoint.getTargetNode() + " should not be null. >> end ");
            } else {
                int clickCount = counter.getClickCount();
                boolean stillSincePress = counter.isStill();
                boolean primaryButtonDown = false;
                boolean secondaryButtonDown = false;
                boolean longpressDetected = this.longPressDetector.getLongpressDetected().getValue();
                MouseButton button = !longpressDetected ? MouseButton.PRIMARY : MouseButton.SECONDARY;

                try {
                    Thread.sleep(50L);
                } catch (InterruptedException var10) {
                }

                this.processFullPDR(touchPoint, button, true);
                this._fireMouseEvents(touchPoint, clickCount, stillSincePress, primaryButtonDown, secondaryButtonDown, button);
            }
        }

    }

    private void startFullDrag(EventTarget source) {
        if (this.dragDetected != MouseEventRecognizer.DragDetectedState.PROCESSING && this.dragDetected != MouseEventRecognizer.DragDetectedState.DONE) {
            LogUtils.error("Cannot start full drag outside of DRAG_DETECTED event handler. dragDetected=" + this.dragDetected + " " + this + " target=" + this.getTargetNode());
        }

        this.enterFullPDR(source);
    }

    private void enterFullPDR(EventTarget dragGestureSource) {
        this.fullPDREntered = true;
        this.fullPDRCurrentTarget = null;
        this.fullPDRSource = dragGestureSource;
        this.fullPDRCurrentEventTargets.clear();
    }

    private void exitFullPDR(TuioTouchPoint touchPoint, MouseButton button) {
        this.dragDetected = MouseEventRecognizer.DragDetectedState.NOT_YET;
        this.getTargetNode().getProperties().put("startFullDrag", "false");
        if (this.fullPDREntered) {
            this.fullPDREntered = false;

            for (int i = this.fullPDRCurrentEventTargets.size() - 1; i >= 0; --i) {
                EventTarget entered = this.fullPDRCurrentEventTargets.get(i);
                TuioTouchPoint exitedTouchPoint = touchPoint.copyFor(entered);
                this.fireMouseDragEvent(exitedTouchPoint, MouseDragEvent.MOUSE_DRAG_EXITED_TARGET, true, false, 1, button, this.fullPDRSource);
            }

            this.fullPDRCurrentTarget = null;
            this.fullPDRSource = null;
            this.fullPDRCurrentEventTargets.clear();
        }
    }

    private void processFullPDR(TuioTouchPoint touchPoint, MouseButton button, boolean releaseEvent) {
        EventTarget eventTarget = touchPoint.getCurrentTargetNode();
        if (!this.fullPDREntered) {
            this.exitFullPDR(touchPoint, button);
        } else {
            if (eventTarget != this.fullPDRCurrentTarget) {
                this.fillHierarchy(this.fullPDRNewEventTargets, (Node) eventTarget);
                int newTargetsSize = this.fullPDRNewEventTargets.size();
                int i = this.fullPDRCurrentEventTargets.size() - 1;

                int j;
                for (j = newTargetsSize - 1; i >= 0 && j >= 0 && this.fullPDRCurrentEventTargets.get(i) == this.fullPDRNewEventTargets.get(j); --j) {
                    --i;
                }

                EventTarget enteredEventTarget;
                TuioTouchPoint enteredTouchPoint;
                while (i >= 0) {
                    enteredEventTarget = this.fullPDRCurrentEventTargets.get(i);
                    enteredTouchPoint = touchPoint.copyFor(enteredEventTarget);
                    this.fireMouseDragEvent(enteredTouchPoint, MouseDragEvent.MOUSE_DRAG_EXITED_TARGET, true, false, 1, button, this.fullPDRSource);
                    --i;
                }

                while (j >= 0) {
                    enteredEventTarget = this.fullPDRNewEventTargets.get(j);
                    enteredTouchPoint = touchPoint.copyFor(enteredEventTarget);
                    this.fireMouseDragEvent(enteredTouchPoint, MouseDragEvent.MOUSE_DRAG_ENTERED_TARGET, true, false, 1, button, this.fullPDRSource);
                    --j;
                }

                this.fullPDRCurrentTarget = eventTarget;
                this.fullPDRCurrentEventTargets.clear();
                this.fullPDRCurrentEventTargets.addAll(this.fullPDRNewEventTargets);
            }

            TuioTouchPoint newTouchPoint = touchPoint.copyFor(eventTarget);
            if (eventTarget != null && !releaseEvent) {
                this.fireMouseDragEvent(newTouchPoint, MouseDragEvent.MOUSE_DRAG_OVER, true, false, 1, button, this.fullPDRSource);
            }

            if (eventTarget != null && releaseEvent) {
                this.fireMouseDragEvent(newTouchPoint, MouseDragEvent.MOUSE_DRAG_RELEASED, true, false, 1, button, this.fullPDRSource);
                this.exitFullPDR(touchPoint, button);
            }

        }
    }

    private void _fireMouseEvents(TuioTouchPoint touchPoint, int clickCount, boolean stillSincePress, boolean primaryButtonDown, boolean secondaryButtonDown, MouseButton button) {
        this.fireMouseEvent(touchPoint, MouseEvent.MOUSE_RELEASED, primaryButtonDown, secondaryButtonDown, stillSincePress, clickCount, button);
        this.fireMouseEvent(touchPoint, MouseEvent.MOUSE_CLICKED, primaryButtonDown, secondaryButtonDown, stillSincePress, clickCount, button);
        if (!this.mouseExited) {
            this.fireMouseEvent(touchPoint, MouseEvent.MOUSE_EXITED_TARGET, true, secondaryButtonDown, stillSincePress, clickCount, button);
        }

        this.mouseExited = false;
    }

    private void mouseDragged(TuioTouchPoint touchPoint) {
        if (this.mouseDraggedTouchPoint == null) {
            this.mouseDraggedTouchPoint = (TuioTouchPoint) this.touchPointsList.get(0);
        }

        boolean longpressDetected = this.longPressDetector.getLongpressDetected().getValue();
        MouseButton button = !longpressDetected ? MouseButton.PRIMARY : MouseButton.SECONDARY;
        boolean fireDragEvent = false;
        if (this.mouseDraggedTouchPoint.equals(touchPoint)) {
            this.mouseDraggedTouchPoint = touchPoint;
            if (this.dragDetected == MouseEventRecognizer.DragDetectedState.NOT_YET) {
                fireDragEvent = true;
                this.dragDetected = MouseEventRecognizer.DragDetectedState.PROCESSING;
            }

            this.fireMouseEvent(this.touchPointsList.get(0), MouseEvent.MOUSE_DRAGGED, true, false, false, 1, button, fireDragEvent);
            if (this.fullPDREntered) {
                this.processFullPDR(this.touchPointsList.get(0), button, false);
            }
        } else if (!this.mouseDraggedTouchPoint.equals(this.touchPointsList.get(0)) && (this.touchPointsList.get(0)).equals(touchPoint)) {
            double sceneX = touchPoint.getSceneX() - this.originNextMouseDraggedSceneX + this.mouseDraggedTouchPoint.getSceneX();
            double sceneY = touchPoint.getSceneY() - this.originNextMouseDraggedSceneY + this.mouseDraggedTouchPoint.getSceneY();
            double screenX = touchPoint.getScreenX() - this.originNextMouseDraggedScreenX + this.mouseDraggedTouchPoint.getScreenX();
            double screenY = touchPoint.getScreenY() - this.originNextMouseDraggedScreenY + this.mouseDraggedTouchPoint.getScreenY();
            this.fireMouseEvent(this.touchPointsList.get(0), MouseEvent.MOUSE_DRAGGED, sceneX, sceneY, screenX, screenY, true, false, false, 1, button, fireDragEvent);
        }

        if (this.dragDetected == MouseEventRecognizer.DragDetectedState.PROCESSING) {
            this.dragDetected = MouseEventRecognizer.DragDetectedState.DONE;
        }

    }

    private static final class CacheEventData {
        private final TuioTouchPoint touchPoint;
        private final int clickCount;
        private final boolean stillSincePress;
        private final boolean primaryButtonDown;
        private final boolean secondaryButtonDown;
        private final MouseButton button;
        private final boolean mouseExited;

        public CacheEventData(TuioTouchPoint touchPoint, int clickCount, boolean stillSincePress, boolean primaryButtonDown, boolean secondaryButtonDown, MouseButton button, boolean mouseExited) {
            this.touchPoint = touchPoint;
            this.clickCount = clickCount;
            this.stillSincePress = stillSincePress;
            this.primaryButtonDown = primaryButtonDown;
            this.secondaryButtonDown = secondaryButtonDown;
            this.button = button;
            this.mouseExited = mouseExited;
        }
    }

    private static enum DragDetectedState {
        NOT_YET,
        PROCESSING,
        DONE;

        private DragDetectedState() {
        }
    }

    private class ClickCounter {
        private int clickCount;
        Toolkit toolkit;
        private Timeline timeout;
        private boolean timeoutIsReached;
        private boolean still;
        private double pressedX;
        private double pressedY;

        private ClickCounter() {
            this.clickCount = 0;
            this.toolkit = Toolkit.getDefaultToolkit();
        }

        int incrementClickCount() {
            return this.clickCount++;
        }

        boolean isTimeoutReached() {
            return this.timeoutIsReached;
        }

        private boolean isStill() {
            return this.still;
        }

        int getClickCount() {
            return this.clickCount;
        }

        private void clear() {
            this.clickCount = 0;
        }

        private void out() {
            this.timeoutIsReached = true;
            this.stopTimeout();
        }

        private void moved(final double x, final double y) {
            Platform.runLater(new Runnable() {
                public void run() {
                    if (Math.abs(x - ClickCounter.this.pressedX) > 10.0 || Math.abs(y - ClickCounter.this.pressedY) > 10.0) {
                        ClickCounter.this.out();
                        ClickCounter.this.still = false;
                    }

                }
            });
        }

        private void start(double x, double y) {
            this.pressedX = x;
            this.pressedY = y;
            if (this.timeoutIsReached) {
                this.clear();
            }

            this.timeoutIsReached = false;
            ++this.clickCount;
            if (this.timeout != null) {
                this.timeout.stop();
            }

            Platform.runLater(new Runnable() {
                public void run() {
                    ClickCounter.this.timeout = new Timeline();
                    ClickCounter.this.timeout.getKeyFrames().add(new KeyFrame(new Duration(Util.getToolkitMultiClickInterval(toolkit)), new EventHandler<ActionEvent>() {
                        public void handle(ActionEvent event) {
                            ClickCounter.this.timeoutIsReached = true;
                            ClickCounter.this.timeout = null;
                        }
                    }, new KeyValue[0]));
                    ClickCounter.this.timeout.play();
                }
            });
            this.still = true;
        }

        private void stopTimeout() {
            if (this.timeout != null) {
                this.timeout.stop();
            }

            this.timeout = null;
        }
    }
}
